package TrainController;

import TrainModel.TrainModel;
import TrackModel.Block;
import TrackModel.StationBlock;
import Utilities.Message;
import Utilities.TrainInfo;
import application.Main;



public class TrainController implements TrainModeltoTrainController, MBOtoTrainController 
{
	private boolean bBrakeFail = false;
	private boolean bEngineFail = false;
	private boolean bSignalFail = false;
    private Message toDoMessage;
    private double dCTCSpeed = 0;
    private double dCTCSuggestion = 0;
	private double dMBOSpeed = 0;
	private double happyplace;
	private double disp = 0;
	private double dLastReceivedSpeed;
	private int iCTCAuthority = 0;
	private int iMBOAuthority = 0;
	private long tickLen;
	private int tID;
	private int waiter;
	private int iWaitingGame;
	private int iStationFlag = 0;
	private int iStopping = 0;
	private String[] toDo = new String[2];
	private String[] theID = new String[2];
	private String[] theAS = new String[2];
	private TrainModel trainModel;
	private VitalOperations vo;
	private String header;
	
	

	public TrainController(int trainId, TrainModel tm, long tickL)
	{
		trainModel = tm;
		tID = trainId;
		tickLen = tickL;
		vo = new VitalOperations(trainModel, trainId);
		Main.registerTrainController(this);
		header = new String("Train "+trainId+" TrainController: ");
	}
	
	public void tick()
	{
		if(!bSignalFail && !bBrakeFail)
		{
			if(iWaitingGame == 0 && (vo.getCTCAuthority() > 1))
			{	
			double dPowerCmd = vo.calcPower(dCTCSpeed,trainModel.getSpeed(),trainModel.getNumPassengers(), tickLen);
				if(bEngineFail == true)
				{
					dPowerCmd = 0;
					vo.throwEBrake();
				}
				else
				{
					trainModel.setPower(dPowerCmd);
				}
			}
			vo.calculateAuthority(trainModel.getCurrentBlock());
			this.setLights();
			this.weatherMan();
			if(iStationFlag == 1)
			{
				this.stationStop();
			}
			if(waiter >= 6){
				this.departure();
			}
		}
		else
		{
			vo.throwEBrake();
		}
		//clearing the fail states to see if the train is still in a fault state on next tick
		bEngineFail = false;
		bSignalFail = false;
		bBrakeFail = false;
		Main.log.write(header+"tick info");
		Main.log.write("\t\tAt block "+trainModel.getCurrentBlock().getBlockID());
	}

	public boolean signalPickup(Message m)
	{
		boolean bIsOn = false;
		if(m != null && iStationFlag == 0)
		{
			toDoMessage = m;
			System.out.println("TrainController is getting this message:" +toDoMessage.sMessage1);
		    toDo = toDoMessage.sMessage1.split("\\|");
		    theID = toDo[0].split(" ");
			int foo = 0;
			foo = Integer.parseInt(theID[1]);
			if(theID[0].equals("T") && foo == tID){
				theAS = toDo[1].split(" ");
				if(theAS[1].equals("A"))
				{
					iCTCAuthority = Integer.parseInt(theAS[2]);
					vo.updateAuthority(true, iCTCAuthority, 0, trainModel.getCurrentBlock());
				}
				else if(theAS[1].equals("S"))
				{
					dCTCSuggestion = Double.parseDouble(theAS[2]);
					dCTCSpeed = dCTCSuggestion;
					if(dCTCSuggestion >= 43)
					{
						dCTCSpeed = 43;
					}

					dLastReceivedSpeed = dCTCSpeed;
					Main.log.write(header+"Updating CTCSpeed to "+dCTCSpeed+"mph");
				}
			}
			bIsOn = true;
		}
		return bIsOn;
	}
	
	
	public boolean reportEngineFailure() 
	{
		bEngineFail = true;
		return true;
	}

	
	public boolean reportBrakeFailure() 
	{
		bBrakeFail = true;
		return true;
	}
	
	
	public boolean reportSignalFailure() 
	{
		bSignalFail = true;
		return true;
	}
	
	private void setLights()
	{
		Block b = trainModel.getCurrentBlock();
		trainModel.setLightsOn(b.isUnderground());
	}
	
	private boolean setDoors(boolean b)
	{
		if(trainModel.getSpeed() <= 0)
		{
			trainModel.setDoorOpen(b);
			Main.log.write(header+"set doors open to "+b);
			return true;
		}
		else
		{
			return false;
		}
	}

	@SuppressWarnings("unused")
	private void eDoors(){
		trainModel.setDoorOpen(true);
	}
	
	
	
	public TrainInfo RequestGPS()
	{
		TrainInfo ti = new TrainInfo();
		/*Block b = trainModel.getCurrentBlock();
		int[] potato = b.getLocation();
		double cSpeed = 0;
		cSpeed = (trainModel.getSpeed()) * 2.2369;//mph
		//Change indices to get methods since it is an arraylist
		//ti.setTrainInfo(potato[0], potato[1], tID, trainModel.getNumPassengers(), cSpeed);
		 
		 */
		return ti;
	}

	public String toString()
	{
		StringBuilder s = new StringBuilder();
		s.append("Train ID: "+tID+",");
		s.append("Current CTCSpeed: "+dCTCSpeed+",");
		s.append("Current CTCAuthority: "+iCTCAuthority+",");
		s.append("Current MBOSpeed: "+dMBOSpeed+",");
		s.append("Current MBOAuthority: "+iMBOAuthority);

		return s.toString();	
	}

	public void arrival(String s) 
	{
		trainModel.setAnnouncements(s);//announce station
		Main.log.write(header+"arrival called and CTC Speed/Authority lockout begins");
		iStationFlag = 1;
		if(!(trainModel.getCurrentBlock() instanceof StationBlock))
		{
			Main.log.write(header+"NOT in station block. Setting speed to 3");
			dCTCSpeed = 3;
		}
	}
	
	public double getCTCSpeed()
	{
		return dCTCSuggestion;
	}
	public int getCTCAuthority()
	{
		return iCTCAuthority;
	}
	private void departure()
	{
		this.setDoors(false);
		vo.serviceBrake(0);
		iStationFlag = 0;
		disp = 0;//displacement into station block
		waiter = 0;
		happyplace = 0;
		iWaitingGame = 0;
		iStopping = 0;
		dCTCSpeed = dLastReceivedSpeed;
		trainModel.setAdvertisements("Smell like success with Dog Fart Express: Dog Fart Express, the only train you'll ever ride (because we gonna die)");
		Main.log.write(header+"departure called and CTC Speed/Authority lockout lifted");
	}

	private void stationStop()
	{
		if(trainModel.getCurrentBlock().hasTransponder && iStationFlag == 1)
		{
			if((trainModel.getSpeed()*2.23694) > 5)
			{
				vo.serviceBrake(.5);
			}
		}
		
		if(trainModel.getCurrentBlock() instanceof StationBlock && iStopping != 1)
		{
			iStopping = 1;
			Main.log.write(header+"in stationStop, procedure stopping beginning");
			Block tempBlock = trainModel.getCurrentBlock();
			double dStop = tempBlock.getLength()/2 + trainModel.getSpeed()*2;
			disp = 0;
			happyplace = tempBlock.getLength() - dStop;
			Main.log.write(header+"stopping distance is "+happyplace+" m  into the block");
		}
		if(disp >= happyplace && iStopping == 1)
			{
			vo.serviceBrake(.6);
			dCTCSpeed = 0;
			Main.log.write(header+"setting speed to 0 and service brake to 60%");
			}
		
		if(trainModel.getSpeed() <= 0 && iStopping == 1)
		{
			this.setDoors(true);
			Main.log.write(header+"stationStop waiting begins");
			iWaitingGame = 1;
		}
		if(iStopping == 1)
		{
			disp = trainModel.getSpeed()*tickLen;
		}
		if(iWaitingGame == 1)
		{
			Main.log.write(header+"stationStop waiting "+ waiter);
			vo.cancelPower();
			waiter++;
		}
	}
	private void weatherMan()
	{
		double dHowsTheWeather = trainModel.getCurrentBlock().getRailTemperature();
		if (dHowsTheWeather < 32)
		{
			trainModel.setThermostat(80);
			Main.log.write(header+" setting the interior temperature to 80");
		}
		else
		{
			trainModel.setThermostat(70);
			Main.log.write(header+" setting the interior temperature to 70");
		}
	}
}
